#include "A_Config.h"
static lv_obj_t *obj_timetable;
static uint8_t curr_week = 0;
static bool class_editing = false;
static alarm_t *alarm_c = NULL;
static bool menu_require = false;
static bool modified = false;
static bool needAnimation = false;
static void btn_timetable_event(lv_event_t *e)
{
    alarm_c = (alarm_t *)lv_obj_get_user_data(lv_event_get_target(e));
    menu_require = true;
}

static void add_button(const char *str, uint16_t sleep = 0, lv_color_t color = lv_palette_main(LV_PALETTE_BLUE), void *user_data = NULL)
{
    lv_obj_t *obj = lv_btn_create(obj_timetable);
    lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
    lv_obj_set_style_bg_color(obj, color, 0);
    lv_obj_t *label = lv_label_create(obj);
    lv_label_set_text(label, str);
    lv_obj_set_style_text_color(label, lv_color_white(), 0);
    lv_obj_set_style_text_font(label, &lv_font_chinese_16, 0);
    lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
    lv_obj_center(label);
    lv_obj_set_user_data(obj, user_data);
    if (needAnimation == true)
        lv_obj_fade_in(obj, 300, sleep);
    lv_obj_add_event_cb(obj, btn_timetable_event, LV_EVENT_CLICKED, NULL);
}

static void insert_button(const char *str, void *user_data)
{
    lv_obj_del(lv_obj_get_child(obj_timetable, -1));
    add_button(str, 0, lv_palette_main(LV_PALETTE_RED), user_data);
    add_button("添加...", 200);
}

/**
 *  @brief 排序、保存数据并提示
 */
static void class_save()
{
    alarm_sort();
    alarm_save();
    modified = false;
}

static uint16_t get_child_id_by_alarm(alarm_t *a)
{
    int16_t i = 0;
    while (1)
    {
        lv_obj_t *b = lv_obj_get_child(obj_timetable, i);
        if (b == NULL)
        {
            i = -1;
            break;
        }
        alarm_t *cur = (alarm_t *)lv_obj_get_user_data(b);
        if (cur == a)
        {
            break;
        }
        ++i;
    }
    return i;
}
/**
 * @brief 删除alarm_c指向的课程
 */
static void class_delete()
{
    lv_obj_del(lv_obj_get_child(obj_timetable, get_child_id_by_alarm(alarm_c)));
    memset(alarm_c, 0, sizeof(alarm_t));
}

static void gotoAlarm(alarm_t *a)
{
    int16_t i = 0;
    if (a == NULL)
        return;
    while (1)
    {
        lv_obj_t *b = lv_obj_get_child(obj_timetable, i);
        if (b == NULL)
        {
            break;
        }
        alarm_t *cur = (alarm_t *)lv_obj_get_user_data(b);
        if (cur == a)
        {
            lv_obj_set_style_bg_color(b, lv_palette_main(LV_PALETTE_BROWN), 0);
            lv_obj_set_scroll_snap_y(obj_timetable, LV_SCROLL_SNAP_CENTER);
            lv_obj_scroll_to_view(lv_obj_get_child(obj_timetable, i), LV_ANIM_ON);
            lv_obj_set_scroll_snap_y(obj_timetable, LV_SCROLL_SNAP_NONE);
        }
        else if (cur)
        {
            if (cur->type == ALARM_CLASS)
                lv_obj_set_style_bg_color(b, lv_palette_main(LV_PALETTE_BLUE), 0);
            if (cur->type == ALARM_USER)
                lv_obj_set_style_bg_color(b, lv_palette_main(LV_PALETTE_YELLOW), 0);
            if (cur->type == ALARM_COUNTDOWN)
                lv_obj_set_style_bg_color(b, lv_palette_main(LV_PALETTE_ORANGE), 0);
        }
        else
        {
            lv_obj_set_style_bg_color(b, lv_palette_main(LV_PALETTE_BLUE), 0);
        }
        ++i;
    }
}

static void class_reload()
{
    uint16_t total = 0;
    while (1)
    {
        auto o = lv_obj_get_child(obj_timetable, 0);
        if (o)
            lv_obj_del(o);
        else
            break;
    }
    alarm_t *n = alarm_get_next(hal.rtc.weekday, hal.rtc.hour * 60 + hal.rtc.minute);
    while (1)
    {
        alarm_t *c = alarm_get_today(curr_week, total);
        if (c == NULL)
            break;
        char buf[40];
        if (c->type == ALARM_CLASS)
        {
            sprintf(buf, "%s %02d:%02d, %d 分钟", c->subtype, c->time_start / 60, c->time_start % 60, c->time_end - c->time_start);
            add_button(buf, total * 50, lv_palette_main(LV_PALETTE_BLUE), c);
        }
        else if (c->type == ALARM_USER)
        {
            sprintf(buf, "闹钟, 时间 %02d:%02d", c->time_start / 60, c->time_start % 60);
            add_button(buf, total * 50, lv_palette_main(LV_PALETTE_YELLOW), c);
        }
        else if (c->type == ALARM_COUNTDOWN)
        {
            sprintf(buf, "倒计时, 时间 %02d:%02d", c->time_start / 60, c->time_start % 60);
            add_button(buf, total * 50, lv_palette_main(LV_PALETTE_ORANGE), c);
        }
        ++total;
    }
    add_button("添加...", total * 50);
    gotoAlarm(n);
    alarm_c = n;
}

/**
 * @brief 选择星期菜单
 */
static void change_week()
{
    menu_create();
    for (uint8_t i = 1; i <= 7; ++i)
    {
        menu_add(week_name[i]);
    }
    uint8_t tmp = menu_show();
    if (tmp != 0)
    {
        class_editing = true;
        if (modified)
        {
            if (msgbox_yn("修改星期会自动保存并刷新当前课程表，是否继续？"))
            {
                curr_week = tmp;
                class_save();
            }
            else
                return;
        }
        curr_week = tmp - 1;
        class_reload();
    }
}
bool cp(File &dst, File &src)
{
    char *buf = (char *)malloc(512);
    size_t size = src.size();
    while (size > 0)
    {
        size_t this_size = src.readBytes(buf, 512);
        if (this_size == 0)
            break;
        size -= this_size;
        size_t wr_size = dst.write((uint8_t *)buf, this_size);
        if (wr_size != this_size)
            break;
    }
    if (size == 0)
        return true;
    else
        return false;
}
static alarm_t *add_class_dialog()
{
    alarm_t a;
    uint16_t t;
    memset(&a, 0, sizeof(alarm_t));
    menu_create();
    menu_add("排序并保存");
    menu_add("退出编辑模式");
    menu_add("添加课程");
    menu_add("添加闹钟");
    menu_add("添加倒计时");
    menu_add("切换当前星期");
    menu_add("备份到TF卡");
    menu_add("恢复备份");
    menu_add("删除全部闹钟");
    switch (menu_show())
    {
    case 0:
        return NULL;
        break;
    case 1:
        class_save();
        class_reload();
        modified = false;
        return NULL;
        break;
    case 2:
        class_editing = false;
        if (modified)
        {
            if (msgbox_yn("是否保存"))
            {
                class_save();
            }
            else
            {
                alarm_load();
            }
            class_reload();
            modified = false;
        }
        return NULL;
        break;
    case 3:
        a.type = ALARM_CLASS;
        break;
    case 4:
        a.type = ALARM_USER;
        break;
    case 5:
        a.type = ALARM_COUNTDOWN;
        break;
    case 6:
        change_week();
        return NULL;
        break;
    case 7:
    {
        File f = SDCARD.open("/alarm.bin", "w");
        if (!f)
        {
            lv_toast("无法打开备份文件");
            return NULL;
        }
        File f_local = SPIFFS.open("/alarm.bin", "r");
        if (!f_local)
        {
            lv_toast("无法打开本地文件");
            f.close();
            return NULL;
        }
        if (cp(f, f_local))
            lv_toast("备份成功");
        else
            lv_toast("备份失败");
        f.close();
        f_local.close();
        return NULL;
        break;
    }
    case 8:
    {
        File f = SDCARD.open("/alarm.bin");
        if (!f)
        {
            lv_toast("不存在备份");
            return NULL;
        }
        File f_local = SPIFFS.open("/alarm.bin", "w");
        if (!f_local)
        {
            lv_toast("无法打开目标文件");
            f.close();
            return NULL;
        }
        if (cp(f_local, f))
        {
            lv_toast("恢复成功");
        }
        else
            lv_toast("恢复失败");
        f.close();
        f_local.close();
        alarm_load();
        int r = alarm_autoFix();
        if (r == 1) // 自动解决从旧版导入星期不匹配的问题
        {
            lv_toast("已自动修复星期问题");
        }
        else if (r == -1)
        {
            lv_toast("文件有问题，已自动删除错误的闹钟");
        }
        alarm_save();
        class_reload();
        modified = false;
        return NULL;
        break;
    }
    case 9:
        if (msgbox_yn("将重建闹钟存储文件\n此操作不可撤销!"))
        {
            if (msgbox_yn("请再次确认，此操作需要输入密码"))
            {
#ifdef CMD_PASSWORD
                if (msgbox_passwd() == CMD_PASSWORD)
                {
#endif
                    alarm_erase();
                    alarm_save();
                    full_screen_msgbox(BIG_SYMBOL_CHECK, "完成", "已清除全部闹钟信息，将于三秒后重启", FULL_SCREEN_BG_CHECK, 3000);
                    ESP.restart();
                    return NULL;
#ifdef CMD_PASSWORD
                }
                else
                {
                    settings.setInt("last_password", 0);
                    settings.writeSettings(CONFIG_FILE_NAME);
                }
#endif
            }
        }
        return NULL;
    default:
        return NULL;
    }
    if (a.type == ALARM_CLASS)
    {
        menu_create();
        uint16_t i = 0;
        while (class_names[i])
        {
            menu_add(class_names[i]);
            ++i;
        }
        t = menu_show() - 1;
        if (t == 0xffff)
            return NULL;
        else
            strcpy(a.subtype, class_names[t]);
    }
    a.week = curr_week;
    // 闹钟、课程时间设置
    if (a.type == ALARM_CLASS)
    {
        a.time_start = msgbox_time("上课时间");
        if (msgbox_yn("是否快速设置40分钟课程时长？"))
        {
            a.time_end = a.time_start + 40;
        }
        else
        {
            a.time_end = msgbox_time("下课时间", a.time_start);
        }
    }
    else
    {
        a.time_end = a.time_start = msgbox_time("开始时间");
    }
    class_editing = true;
    modified = true;
    return alarm_add(a.type, a.subtype, a.week, a.time_start, a.time_end);
}

/**
 *  @brief 修改课程对话框
 */
static void modify_class_dialog()
{
    uint8_t r;
    alarm_t *a = alarm_c;
    uint16_t num = get_child_id_by_alarm(a);
    menu_create();
    menu_add("修改星期");
    menu_add("修改类型");
    menu_add("修改时间");
    menu_add("删除课程");
    menu_add("切换当前星期");
    switch (menu_show())
    {
    case 0:
        return;
    case 1:
        menu_create();
        {
            uint16_t i = 0;
            while (week_name[i])
            {
                menu_add(week_name[i]);
                ++i;
            }
        }
        r = menu_show();
        if (r)
            a->week = r - 1;
        else
            return;
        break;
    case 2:
        menu_create();
        menu_add("改为课程");
        menu_add("改为闹钟");
        menu_add("改为倒计时");
        switch (menu_show())
        {
        case 0:
            return;
            break;
        case 1:
            if (a->type != ALARM_CLASS)
            {
                msgbox(LV_SYMBOL_WARNING " 警告", "已默认此课程为40分钟，开始时间与原时间相同");
                a->time_end = a->time_start + 40;
                if (a->time_end > 23 * 60 + 59)
                    a->time_end = 23 * 60 + 59;
                strcpy(a->subtype, class_names[0]);
            }
            a->type = ALARM_CLASS;
            menu_create();
            {
                uint16_t i = 0;
                while (class_names[i])
                {
                    menu_add(class_names[i]);
                    ++i;
                }
            }
            r = menu_show() - 1;
            if (r != 0xff)
                strcpy(a->subtype, class_names[r]);
            else
                return;
            break;
        case 2:
            a->type = ALARM_USER;
            a->time_end = a->time_start;
            break;
        case 3:
            a->type = ALARM_COUNTDOWN;
            a->time_end = a->time_start;
            break;
        }
        break;
    case 3:
        if (a->type == ALARM_CLASS)
        {
            a->time_start = msgbox_time("上课时间", a->time_start);
            if (msgbox_yn("是否快速设置40分钟课程时长？"))
            {
                a->time_end = a->time_start + 40;
            }
            else
            {
                a->time_end = msgbox_time("下课时间", a->time_end);
            }
        }
        else
        {
            a->time_end = a->time_start = msgbox_time("开始时间", a->time_start);
        }
        break;
    case 4:
        if (msgbox_yn("确定删除？"))
        {
            class_editing = true;
            modified = true;
            class_delete();
        }
        return;
        break;
    case 5:
        change_week();
        return;
        break;
    default:
        return;
    }
    lv_obj_set_style_bg_color(lv_obj_get_child(obj_timetable, num), lv_palette_main(LV_PALETTE_RED), 0);
    class_editing = true;
    modified = true;
}

// 不需要固定每秒循环一次，但是越快越好
void tile_clock_timetable_loop1()
{
    if (menu_require)
    {
        menu_require = false;
        if (alarm_c == NULL)
        {
            alarm_t *a = add_class_dialog();
            if (a != NULL)
            {
                char buf[40];
                if (a->type == ALARM_CLASS)
                {
                    sprintf(buf, "%s %02d:%02d, %d 分钟", a->subtype, a->time_start / 60, a->time_start % 60, a->time_end - a->time_start);
                }
                else if (a->type == ALARM_USER)
                {
                    sprintf(buf, "闹钟, 时间 %02d:%02d", a->time_start / 60, a->time_start % 60);
                }
                else if (a->type == ALARM_COUNTDOWN)
                {
                    sprintf(buf, "倒计时, 时间 %02d:%02d", a->time_start / 60, a->time_start % 60);
                }
                insert_button(buf, a);
            }
        }
        else
        {
            modify_class_dialog();
        }
        if (class_editing)
        {
            lv_obj_add_state(obj_timetable, LV_STATE_USER_1);
        }
        else
        {
            lv_obj_clear_state(obj_timetable, LV_STATE_USER_1);
        }
    }
}

void tile_clock_timetable_loop()
{
    if (class_editing == true)
    {
        hal.canDeepSleep = false;
        return;
    }
    hal.canDeepSleep = true;
    if (hal.rtc.weekday != curr_week)
    {
        curr_week = hal.rtc.weekday;
        class_reload();
    }
    alarm_t *a = alarm_get_next(hal.rtc.weekday, hal.rtc.minute + 60 * hal.rtc.hour);
    if (alarm_c != a)
    {
        alarm_c = a;
        gotoAlarm(a);
    }
}

void tile_clock_timetable_create(lv_obj_t *tile)
{
    obj_timetable = lv_obj_create(tile);
    lv_obj_set_size(obj_timetable, 176, 144);
    lv_obj_set_pos(obj_timetable, 4, 92);
    lv_obj_pop_up(obj_timetable, 50, 500, 400);
    lv_obj_set_flex_flow(obj_timetable, LV_FLEX_FLOW_ROW_WRAP);
    curr_week = hal.rtc.weekday;
    needAnimation = false;
    class_reload();
    needAnimation = true;

    static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, (lv_style_prop_t)0};
    static lv_style_transition_dsc_t trans_def;
    // 正常模式
    lv_style_transition_dsc_init(&trans_def, props, lv_anim_path_linear, 600, 0, NULL);
    static lv_style_t style_def;
    lv_style_init(&style_def);
    lv_style_set_transition(&style_def, &trans_def);

    // 编辑模式
    static lv_style_transition_dsc_t trans_edit;
    lv_style_transition_dsc_init(&trans_edit, props, lv_anim_path_linear, 600, 0, NULL);
    static lv_style_t style_edit;
    lv_style_init(&style_edit);
    lv_style_set_bg_color(&style_edit, lv_palette_lighten(LV_PALETTE_LIGHT_BLUE, 3));
    lv_style_set_transition(&style_edit, &trans_edit);

    lv_obj_add_style(obj_timetable, &style_def, 0);
    lv_obj_add_style(obj_timetable, &style_edit, LV_STATE_USER_1);
}